﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;

namespace nbcs_chess_squad
{
    public partial class GameForm : Form
    {
        #region Variables
        //
        //Game Setup
        //
        BoardSquare[,] Chessboard = new BoardSquare[8, 8];
        Piece[] piece = new Piece[32];

        //
        //Game Variables
        //
        Coordinates squareCoordinates = new Coordinates();
        BoardSquare originSquare = new BoardSquare();
        BoardSquare targetBoardSquare;
        bool pathObstructed;
        bool WhitesTurn = true;
        //true = player 1 (white), false = player 2 (black)
        public bool playercolor;
        public string PlayerName;
        bool verifyName;

        //
        //Network Variables
        //
        Network objNetwork;
        public bool wNetworkPlay = false;
        string wServerIP = "";
        public bool wServer = false;
        public bool wClient = false;
        public bool connected = false;

        //Misc
        delegate void UpdatetxtIPDelegate(string IP);

        #endregion

        #region Initialization/Load
        public GameForm()
        {
            InitializeComponent();
            txtLog.BackColor = Color.White;
        }

        public void GameForm_Load(object sender, EventArgs e)
        {
            objNetwork = new Network(this);
            PrepareBoard();
        }
        #endregion

        private void PrepareBoard()
        {
            CreateBoardArrary();
            CreatePieces();
            SetPiecesOnBoard();
        }

        public void CreateBoardArrary()
        {
            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                {
                    Chessboard[x, y] = new BoardSquare(x, y);
                    Chessboard[x, y].Click += new System.EventHandler(pbSquare_Click);
                    splitContainer1.Panel2.Controls.Add(Chessboard[x, y]);
                }
            }
        }

        private void CreatePieces()
        {
            for (int i = 0; i < 32; i++)
            {
                piece[i] = new Piece();
                piece[i].SetTeamAndImage(i);
            }
        }

        private void SetPiecesOnBoard()
        {
            int x = 0;
            int y = 1;
            //Setup the Pawns
            //Use for loop on coordinates instead of individual assignment
            for (int i = 0; i < 16; i++)
            {
                Chessboard[x, y].Piece = piece[i];
                Chessboard[x, y].ArrayNumber = i;
                Chessboard[x, y].Image = piece[i].Image;

                x++;

                if (i == 7)
                {
                    y = 6;
                    x = 0;
                }
            }

            //Castle
            Chessboard[0, 0].Piece = piece[16];
            Chessboard[0, 0].ArrayNumber = 16;
            Chessboard[0, 0].Image = piece[16].Image;
            Chessboard[7, 0].Piece = piece[17];
            Chessboard[7, 0].ArrayNumber = 17;
            Chessboard[7, 0].Image = piece[17].Image;
            Chessboard[0, 7].Piece = piece[18];
            Chessboard[0, 7].ArrayNumber = 18;
            Chessboard[0, 7].Image = piece[18].Image;
            Chessboard[7, 7].Piece = piece[19];
            Chessboard[7, 7].ArrayNumber = 19;
            Chessboard[7, 7].Image = piece[19].Image;

            //Knight
            Chessboard[1, 0].Piece = piece[20];
            Chessboard[1, 0].ArrayNumber = 20;
            Chessboard[1, 0].Image = piece[20].Image;
            Chessboard[6, 0].Piece = piece[21];
            Chessboard[6, 0].ArrayNumber = 21;
            Chessboard[6, 0].Image = piece[21].Image;
            Chessboard[1, 7].Piece = piece[22];
            Chessboard[1, 7].ArrayNumber = 22;
            Chessboard[1, 7].Image = piece[22].Image;
            Chessboard[6, 7].Piece = piece[23];
            Chessboard[6, 7].ArrayNumber = 23;
            Chessboard[6, 7].Image = piece[23].Image;

            //Bishop
            Chessboard[2, 0].Piece = piece[24];
            Chessboard[2, 0].ArrayNumber = 24;
            Chessboard[2, 0].Image = piece[24].Image;
            Chessboard[5, 0].Piece = piece[25];
            Chessboard[5, 0].ArrayNumber = 25;
            Chessboard[5, 0].Image = piece[25].Image;
            Chessboard[2, 7].Piece = piece[26];
            Chessboard[2, 7].ArrayNumber = 26;
            Chessboard[2, 7].Image = piece[26].Image;
            Chessboard[5, 7].Piece = piece[27];
            Chessboard[5, 7].ArrayNumber = 27;
            Chessboard[5, 7].Image = piece[27].Image;
        }

        public void InitializeMovement()
        {
            if (WhitesTurn == playercolor)
            {
                if (targetBoardSquare.BackColor == Color.Green || targetBoardSquare.BackColor == Color.Yellow)
                {
                    MovePiece(originSquare.Coordinates.X, originSquare.Coordinates.Y, targetBoardSquare.Coordinates.X, targetBoardSquare.Coordinates.Y, false);
                }

                else if (targetBoardSquare.Piece != null && WhitesTurn == targetBoardSquare.Piece.IsWhite)
                {
                    PossibleMoves();
                }

                else
                {
                    ClearBoardMarkings();
                }
            }
        }

        private void MarkSquare()
        {
            //Confirms that the newSquareCoords are a valid pair of coordinates on the board
            if (squareCoordinates.X <= 7 && squareCoordinates.Y <= 7 && squareCoordinates.X >= 0 && squareCoordinates.Y >= 0)
            {
                if (Chessboard[squareCoordinates.X, squareCoordinates.Y].Piece != null)
                {
                    if (Chessboard[squareCoordinates.X, squareCoordinates.Y].Piece.IsWhite != Chessboard[originSquare.Coordinates.X, originSquare.Coordinates.Y].Piece.IsWhite)
                    {
                        Chessboard[squareCoordinates.X, squareCoordinates.Y].BackColor = Color.Yellow;
                        pathObstructed = true;
                    }

                    if (Chessboard[squareCoordinates.X, squareCoordinates.Y].Piece.IsWhite == Chessboard[originSquare.Coordinates.X, originSquare.Coordinates.Y].Piece.IsWhite)
                    {
                        Chessboard[squareCoordinates.X, squareCoordinates.Y].BackColor = Color.Transparent;
                        pathObstructed = true;
                    }
                }

                else if (Chessboard[squareCoordinates.X, squareCoordinates.Y].BackColor == Color.Transparent)
                {
                    Chessboard[squareCoordinates.X, squareCoordinates.Y].BackColor = Color.Green;
                }
            }

            else
            {
                pathObstructed = true;
            }
        }

        public void MovePiece(int originX, int originY, int finalX, int finalY, bool netMove)
        {
            if (connected == true && netMove == false)
            {
                objNetwork.SendMove(originSquare.Coordinates.X, originSquare.Coordinates.Y, targetBoardSquare.Coordinates.X, targetBoardSquare.Coordinates.Y);
            }

            Chessboard[finalX, finalY].Piece = Chessboard[originX, originY].Piece;
            Chessboard[finalX, finalY].ArrayNumber = Chessboard[originX, originY].ArrayNumber;
            Chessboard[finalX, finalY].Image = Chessboard[originX, originY].Image;
            Chessboard[originX, originY].ArrayNumber = -1;
            Chessboard[originX, originY].Piece = null;
            Chessboard[originX, originY].Image = null;
            PieceTests(finalX, finalY);
            ClearBoardMarkings();
            if (WhitesTurn == true)
            {
                WhitesTurn = false;
                toolStripStatusLabel1.Text = ("Black Player's Turn...");
            }

            else
            {
                WhitesTurn = true;
                toolStripStatusLabel1.Text = ("White Player's Turn...");
            }

        }

        private void ClearBoardMarkings()
        {
            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                {
                    Chessboard[x, y].BackColor = Color.Transparent;
                }

            }
        }

        private void ResetBoard()
        {
            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                {
                    Chessboard[x, y].Piece = null;
                    Chessboard[x, y].ArrayNumber = -1;
                    Chessboard[x, y].Image = null;
                }

            }
        }

        private void PossibleMoves()
        {
            ClearBoardMarkings();
            originSquare = targetBoardSquare;
            targetBoardSquare.BackColor = Color.Blue;
            squareCoordinates = targetBoardSquare.Coordinates;
            int counter = 0;

            switch (targetBoardSquare.Piece.Type)
            {
                //Pawn
                case ("Pawn"):
                    if (targetBoardSquare.Piece.HasNotMoved == true)
                    {
                        for (int i = 0; i < 2; i++)
                        {
                            squareCoordinates = piece[targetBoardSquare.ArrayNumber].PossibleMovement(squareCoordinates.X, squareCoordinates.Y, 0);
                            MarkSquare();
                            if (pathObstructed == true)
                            {
                                break;
                            }
                        }
                    }

                    else
                    {
                        squareCoordinates = piece[targetBoardSquare.ArrayNumber].PossibleMovement(squareCoordinates.X, squareCoordinates.Y, 0);
                        MarkSquare();
                    }

                    //Special Attack
                    for (int i = 0; i < 2; i++)
                    {
                        if (i == 1)
                        {
                            squareCoordinates = piece[originSquare.ArrayNumber].SpecialAttack(originSquare.Coordinates.X, originSquare.Coordinates.Y, true);
                        }

                        else
                        {
                            squareCoordinates = piece[originSquare.ArrayNumber].SpecialAttack(originSquare.Coordinates.X, originSquare.Coordinates.Y, false);
                        }

                        if (squareCoordinates.X <= 7 && squareCoordinates.Y <= 7 && squareCoordinates.X >= 0 && squareCoordinates.Y >= 0)
                        {
                            if (Chessboard[squareCoordinates.X, squareCoordinates.Y].Piece != null)
                            {
                                MarkSquare();
                            }
                        }

                    }


                    pathObstructed = false;
                    break;


                case ("Castle"):

                    while (counter < 4)
                    {
                        squareCoordinates = piece[targetBoardSquare.ArrayNumber].PossibleMovement(squareCoordinates.X, squareCoordinates.Y, counter);
                        MarkSquare();

                        if (pathObstructed == true)
                        {
                            counter++;
                            squareCoordinates = targetBoardSquare.Coordinates;
                            pathObstructed = false;
                        }
                    }

                    counter = 0;
                    break;

                case ("Bishop"):

                    while (counter < 4)
                    {
                        squareCoordinates = piece[targetBoardSquare.ArrayNumber].PossibleMovement(squareCoordinates.X, squareCoordinates.Y, counter);
                        MarkSquare();

                        if (pathObstructed == true)
                        {
                            counter++;
                            squareCoordinates = targetBoardSquare.Coordinates;
                            pathObstructed = false;
                        }
                    }
                    break;

                case ("Knight"):

                    while (counter < 8)
                    {
                        squareCoordinates = piece[targetBoardSquare.ArrayNumber].PossibleMovement(squareCoordinates.X, squareCoordinates.Y, counter);
                        MarkSquare();

                        if (pathObstructed == true)
                        {
                            pathObstructed = false;
                        }

                        squareCoordinates = targetBoardSquare.Coordinates;
                        counter++;
                    }
                    break;

            }
        }

        private void PieceTests(int x, int y)
        {
            switch (Chessboard[x, y].Piece.Type)
            {
                //Pawn
                case ("Pawn"):
                    if (piece[Chessboard[x, y].ArrayNumber].HasNotMoved == true)
                    {
                        piece[Chessboard[x, y].ArrayNumber].HasNotMoved = false;
                    }
                    break;
            }
            
        }

        public void RestartGame()
        {
            ResetBoard();
            SetPiecesOnBoard();
            ClearBoardMarkings();
        }

        public void SetStatusMessage(string pMensagem)
        {
            tssMessage.Text = pMensagem;
        }

        delegate void UpdateLogDelegate(string Message);

        public void UpdateLog(string Message)
        {
            if (txtLog.InvokeRequired)
            {
                UpdateLogDelegate del = new UpdateLogDelegate(UpdateLog);
                txtLog.Invoke(del, new object[] { Message });
            }

            else
            {
                txtLog.Text = txtLog.Text + "\r\n" + Message;
            }
        }

        public void UpdatetxtIP(string IP)
        {
            if (txtLog.InvokeRequired)
            {
                UpdateLogDelegate del = new UpdateLogDelegate(UpdatetxtIP);
                txtIp.Invoke(del, new object[] { IP });
            }

            else
            {
                txtIp.Text = IP + " (host)";
            }
        }

        #region Interface Events
        private void pbSquare_Click(object sender, EventArgs e)
        {
            targetBoardSquare = (BoardSquare)sender;
            InitializeMovement();
        }

        private void btnHost_Click(object sender, EventArgs e)
        {
            PlayerName = txtUser.Text;
            verifyName = PlayerName.All(Char.IsLetter) && PlayerName != string.Empty;

            if (verifyName == true)
            {
                wServer = true;
                objNetwork.StartServer();
                SetStatusMessage("Waiting for connection...");
                btnHost.Enabled = false;
                txtUser.Enabled = false;
                txtIp.Enabled = false;
                btnConnectDisconnect.Text = "Disconnect";
            }

            else
            {
                MessageBox.Show("Please enter a valid username containing only characters", "Invalid Username", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        public void btnConnectDisconnect_Click(object sender, EventArgs e)
        {
            PlayerName = txtUser.Text;
            verifyName = PlayerName.All(Char.IsLetter) && PlayerName != string.Empty;

            if (verifyName == true)
            {
                if (btnConnectDisconnect.Text == "Disconnect")
                {
                    if (wServer == true)
                    {
                        //Send disconnect message to client
                        objNetwork.SendDisconnectPacket();
                    }

                    objNetwork.Disconnect();
                    wServer = false;
                    wClient = false;

                    btnConnectDisconnect.Enabled = true;
                    btnHost.Enabled = true;
                    txtUser.Enabled = true;
                    txtIp.Enabled = true;
                    RestartGame();

                    SetStatusMessage("Disconnected at users request");
                    btnConnectDisconnect.Text = "Connect";
                }

                else
                {
                    wServerIP = txtIp.Text;
                    wClient = true;
                    objNetwork.ConnectServer(wServerIP);
                    SetStatusMessage("Connecting...");
                    btnHost.Enabled = false;
                    btnHost.Enabled = false;
                    txtUser.Enabled = false;
                    txtIp.Enabled = false;
                    btnConnectDisconnect.Text = "Disconnect";
                }
            }

            else
            {
                MessageBox.Show("Please enter a valid username containing only characters", "Invalid Username", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (connected == true)
            {
                objNetwork.SendMessage("." + PlayerName + ": " + txtMessage.Text);
            }

            UpdateLog(PlayerName + ": " + txtMessage.Text);
            txtMessage.Text = string.Empty;
        }
    }
}
